当异步任务完成,调用对应回调函数(一般有两个:成功回调和失败回调),并将数据或错误以函数参数传入
PromiseES6 新增的 API,目的是为了解决异步处理中回调函数方式的一些问题:
Promise 如何解决?
.then(...).then(...) 打平,无需嵌套Promise 的状态只能够改变一次(pending → resolved 或 pending → rejected)Promise 可以完全代替回调函数?
不能!
Promise 只能修改一次状态,无法实现多次回调Generator 函数Generator 函数可以退出,并在稍后重新进入,其上下文(变量绑定)会在重新进入时保存
function* 声明创建一个 Generator 函数对象。每次调用 Generator 函数时,它都会返回一个新的 Generator 对象,该对象符合[[011.迭代协议#迭代器协议|迭代器协议]]。当迭代器的 next() 方法被调用时,生成器函数的主体会被执行,直到遇到第一个 yield 表达式,该表达式指定了迭代器要返回的值,或者用 yield* 委托给另一个生成器函数。next() 方法返回一个对象,其 value 属性包含了 yield 表达式的值,done 属性是布尔类型,表示生成器是否已经返回了最后一个值。如果 next() 方法带有参数,那么它会恢复生成器函数的执行,并用参数替换暂停执行的 yield 表达式
其本质就是一个状态机,详见:[[010.Generator 函数|Generator 函数]]
async、awaitPromise + GeneratorFunction 的语法糖,可以写看起来像同步的代码而完成异步编程
示例:
function* fetchUser() {
const data = yield fetch('/api/user');
console.log(data);
}
// 手动执行(实际中常用 co 库或 async/await)
const g = fetchUser();
g.next().value.then(data => g.next(data));
function loadScript(src) {
// 初始状态:pending,数据:undefined
// 状态改变后无法逆转
return new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = src
script.onload = () = resolve(src) // 状态:fulfilled,数据:result
script.onerror = err => reject(err) // 状态:rejected,数据:error
document.head.append(script)
})
}
loadScript('./1.js')
.then(() => loadScript('./2.js'))
.then(() => loadScript('./3.js'))
.catch(err => console.log(err))
Promise.prototype.then(onFulfilled, [onRejected]): Promise
then 的链式调用:前一个 then 的返回值决定下一个 then 函数的参数值Promise.prototype.catch(onError): Promise
then 的语法糖Promise.resolve(1): PromisePromise.reject(new Error('unknown error')): PromisePromise.all(PromiseArray): Promise
Promise 实例(并行),结果都要PromiseArray:包含多个 Promise 实例或普通数据的可迭代对象Promise 也会继续执行,无法中断rejected,整体结果 rejectedPromise.race(PromiseArray): Promise
Promise 实例(并行),竞速:只要一个结果(谁快要谁)PromiseArray:包含多个 Promise 实例或普通数据的可迭代对象Promise 也会继续执行,无法中断// Promise.all
const p1 = Promise.resolve(1)
const p2 = 2
const p3 = Promise.resolve(3)
Promise.all([p1, p2, p3]).then(result => {
console.log(result) // [1, 2, 3]
})
// Promise.race
const p1 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000)
})
}
const p2 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(2), 0)
})
}
Promise.race([p1(), p2()]).then(result => {
console.log(result) // 2
)
new Promise(executor) 中的 executor 函数体的代码是同步执行的.then(onfulfilled, onrejected) 中的 onfulfilled 和 onrejected 回调函数是放入微任务队列,放入时机:
.then 时 Promise 还是 pending:当 Promise 完成时(resolve 或 reject)放入.then 时 Promise 状态已改变:立即放入.then 就产生一个新的 Promise 并作为返回值(.then 的链式调用),其状态取决于该 then 中回调函数的返回值:
resolved),相当于:Promise.resolve(返回值)Promise:[[#状态吸收]].catch 同理,它只是 .then 的语法糖.finally 也会产生一个新的 Promise 并作为返回值,其状态和当前 Promise 状态一致(没有状态吸收)
onFinally 没有参数,返回值也会被忽略await xxx:xxx 同步执行,如果不是一个 Promise 则使用 Promise.resolve() 包裹
Promise 完成后把后面所有的执行语句推入到微任务队列async 函数就产生一个新的 Promise 并作为返回值,其状态取决于该函数的返回值:
resolved),相当于:Promise.resolve(返回值)Promise:[[#状态吸收]]async 函数具有传染性,消除传染性:
Promise,在该 Promise 中进行异步操作,在外部捕获该错误,Promise 完成后再次调用函数<Suspense fallback={Loading}>child</Suspense> 就是如此实现的Promise 状态吸收是指:
以下三种情况下,涉及 Promise 的状态吸收:
// 情况 1: .then 的参数回调函数返回了一个 Promise(.catch 一样)
const p2 = p.then(() => p1)
// p2 要吸收 p1 的状态
// 情况 2: async 函数返回了一个 Promise
const p4 = await asyncFunc()
async function asyncFunc() {
return p3
}
// p4 要吸收 p3 的状态
// 情况 3: resolve 接收了一个 Promise(reject 一样)
const p6 = new Promise((resolve, reject) => {
resolve(p5)
})
// p6 要吸收 p5 的状态
// 注意:Promise.resolve() 接收 Promise 参数不会状态吸收
const p8 = Promise.resolve(p7)
// 这里的 p8 === p7
// 注意:finally() 返回的新 Promise p10 与 p9 状态一致,但没有状态吸收
const p10 = p9.finally()
Promise A+ 规范没有详细规定如何状态吸收,如何保持状态一致取决于 JS 引擎具体实现,下面说一下 Chrome 和 Node.js 的 V8 的实现方式
V8 将状态吸收分为两个步骤:
每一个步骤都是放到微队列中运行
拿上面的情况 1 举例:
p1 完成后p2 状态 = p1 状态 推入微队列,相当于 p1.then(() => p2 状态 = p1 状态)p2 状态 = p1 状态 执行,这时 p2 完成了且状态与 p1 一致async function async1() {
console.log(1);
await async2();
console.log(2);
}
async function async2() {
console.log(3);
}
console.log(4);
setTimeout(function () {
console.log(5);
}, 0)
async1();
new Promise(function (resolve) {
console.log(6);
resolve();
}).then(function () {
console.log(7);
});
console.log(8);
4 1 3 6 8 2 7 5
console.log(1);
setTimeout(() => {
console.log(2);
Promise.resolve().then(() => {
console.log(3);
})
}, 0);
new Promise(function (resolve, reject) {
console.log(4);
setTimeout(function () {
console.log(5);
resolve(6);
}, 0);
}).then((res) => {
console.log(7);
setTimeout(() => {
console.log(res);
}, 0);
})
1 4 2 3 5 7 6
const p = function() {
return new Promise((resolve, reject) => {
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 0);
resolve(2);
});
p1.then((res) => {
console.log(res);
})
console.log(3);
resolve(4);
});
}
p().then((res) => {
console.log(res);
});
console.log ('end');
3 end 2 4
const p = function() {
return new Promise((resolve, reject) => {
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 0);
// resolve(2);
});
p1.then((res) => {
console.log(res);
})
console.log(3);
resolve(4);
});
}
p().then((res) => {
console.log(res);
});
console. log ('end');
3 end 4 1
async function f1() {
console.log(1)
await f2()
console.log(2)
}
f2 = async () => {
await setTimeout(() => {
Promise.resolve().then(() => {
console.log(3)
})
console.log(4)
})
}
f3 = async () => {
Promise.resolve().then(() => {
console.log(6)
})
}
f1()
console.log(7)
f3()
async function f1() {
console.log(1)
await f2()
console.log(2)
}
f2 = async () => {
await (async () => {
await (() => {
console.log(3)
})()
console.log(4)
})()
}
f3 = async () => {
Promise.resolve().then(() => {
console.log(6)
})
}
f1()
console.log(7)
f3()
1 3 7 4 6 2
const p1 = new Promise((resolve, reject) => {
resolve()
})
const p2 = new Promise((resolve, reject) => {
resolve(p1)
})
p2.then(() => {
console.log('1')
})
.then(() => {
console.log('2')
})
.then(() => {
console.log('3')
})
p1.then(() => {
console.log('4')
})
.then(() => {
console.log('5')
})
.then(() => {
console.log('6')
})
4 5 1 6 2 3
async function async1() {
console.log(1)
await async2()
console.log('AAA')
}
async function async2() {
return Promise.resolve(2)
}
async1()
Promise.resolve()
.then(() => console.log(3))
.then(() => console.log(4))
.then(() => console.log(5))
1 3 4 AAA 5
async function async1() {
console.log(1)
await async2()
console.log('AAA')
}
function async2() {
return Promise.resolve(2)
}
async1()
Promise.resolve()
.then(() => console.log(3))
.then(() => console.log(4))
.then(() => console.log(5))
1 AAA 3 4 5
Promise.resolve().then(() => {
console.log(0)
return Promise.resolve(4)
}).then(res => {
console.log(res)
})
Promise.resolve().then(() => {
console.log(1)
}).then(res => {
console.log(2)
}).then(res => {
console.log(3)
}).then(res => {
console.log(5)
}).then(res => {
console.log(6)
})